/*-------------------------------------------------------------------------
 *
 * sasl.h
 *	  定义后端的SASL机制接口。
 *
 * 每个SASL机制定义一个前端和一个后端回调结构。
 *
 * 参见src/interfaces/libpq/fe-auth-sasl.h以获取前端对应项。
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/libpq/sasl.h
 *
 *-------------------------------------------------------------------------
 */

#ifndef PG_SASL_H
#define PG_SASL_H

#include "lib/stringinfo.h"
#include "libpq/libpq-be.h"

/* 消息交换的状态码 */
#define PG_SASL_EXCHANGE_CONTINUE		0
#define PG_SASL_EXCHANGE_SUCCESS		1
#define PG_SASL_EXCHANGE_FAILURE		2

/*
 * 后端SASL机制回调。
 *
 * 要实现后端机制，请声明一个pg_be_sasl_mech结构，并实现适当的回调。
 * 然后，在ClientAuthentication()中的CheckSASLAuth()期间，将机制传递给
 * 当服务器决定使用哪种身份验证方法时。
 */
typedef struct pg_be_sasl_mech
{
	/*---------
	 * get_mechanisms()
	 *
	 * 检索此实现支持的SASL机制名称列表。
	 *
	 * 输入参数：
	 *
	 *	port：客户端端口
	 *
	 * 输出参数：
	 *
	 *	buf：字符串信息缓冲区，回调应将支持的机制名称填充到此缓冲区。
	 *		  名称附加到此StringInfo中，每个名称后面以'\0'字节结束。
	 *---------
	 */
	void		(*get_mechanisms) (Port *port, StringInfo buf);

	/*---------
	 * init()
	 *
	 * 初始化连接的机制特定状态。此回调
	 * 必须返回指向其分配状态的指针，该指针将被
	 * 原样作为第一个参数传递给其他回调。
	 *
	 * 输入参数：
	 *
	 *	port:        客户端端口。
	 *
	 *	mech:        客户端使用的实际机制名称。
	 *
	 *	shadow_pass: 正在验证角色的存储秘密，如果不存在则为
	 *				 NULL。不使用阴影条目的机制可以忽略此参数。
	 *				 如果一个机制使用阴影条目但shadow_pass为NULL，
	 *				 实现必须继续交换，仿佛用户存在且密码不匹配，
	 *				 以避免泄露有效的用户名。
	 *---------
	 */
	void	   *(*init) (Port *port, const char *mech, const char *shadow_pass);

	/*---------
	 * exchange()
	 *
	 * 产生一个要发送给客户端的服务器挑战。该回调
	 * 必须返回PG_SASL_EXCHANGE_*值之一，具体取决于
	 * 交换是否继续、是否成功完成或是否失败。
	 *
	 * 输入参数：
	 *
	 *	state:	  init()返回的不可见机制状态
	 *
	 *	input:	  客户端发送的响应数据，如果机制是
	 *			  客户端优先但客户端未发送初始响应，则为NULL。
	 *			  （这只能在客户端的第一条消息中发生。）这保证是
	 *			  以null结尾以确保安全，但SASL允许在响应中嵌入
	 *			  null，因此机制必须小心检查inputlen。
	 *
	 *	inputlen: 服务器发送的挑战数据的长度，如果客户端未发送初始响应则为-1
	 *
	 * 输出参数，由回调函数设置：
	 *
	 *	output:    一个使用palloc分配的缓冲区，包含服务器的下一个
	 *			   挑战（如果返回PG_SASL_EXCHANGE_CONTINUE）或
	 *			   服务器的结果数据（如果返回PG_SASL_EXCHANGE_SUCCESS，
	 *			   并且机制在成功结果期间需要发送数据）。如果交换
	 *			   完成且不应发送输出，则回调应将其设置为NULL，这对应于
	 *			   PG_SASL_EXCHANGE_FAILURE或PG_SASL_EXCHANGE_SUCCESS
	 *			   但没有结果数据。
	 *
	 *  outputlen: 挑战数据的长度。如果*output为NULL，则忽略。
	 *
	 *	logdetail: 设置为可选的详细信息消息，以打印到
	 *			   服务器日志，以消歧失败模式。（客户端
	 *			   只会看到相同的通用身份验证失败消息。）如果交换
	 *			   在PG_SASL_EXCHANGE_SUCCESS下完成，则忽略。
	 *---------
	 */
	int			(*exchange) (void *state,
							 const char *input, int inputlen,
							 char **output, int *outputlen,
							 const char **logdetail);
} pg_be_sasl_mech;

/* auth.c的通用实现 */
extern int	CheckSASLAuth(const pg_be_sasl_mech *mech, Port *port,
						  char *shadow_pass, const char **logdetail);

#endif							/* PG_SASL_H */
